package com.spring.framework.config.bean;

import com.spring.framework.config.bean.model.ScopeDemo;
import com.spring.framework.model.learn.ReflectWarning;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * 在Spring的一系列Component组件注解或者@Configuration配置注解标注的类的内部，可以使用@Bean注解标注方法，表示向IoC容器添加bean定义。
 *
 * @author xuweizhi
 * @since 2020/12/11 17:48
 */
@Configuration
@ComponentScan(basePackages ={"com.spring.framework.config.bean"})
public class BeanConfig extends ReflectWarning {

	/**
	 * ps: @Bean的作用同样类似于< bean >标签，和@Component系列注解的区别是相当于使用工厂模式实例化bean。
	 * <p>
	 * 即我们在方法中编写实例化bean的逻辑，然后返回该bean，这样bean就会被注册到IoC容器中，IoC容器会自动调用该方法创建bean实例。
	 * <p>
	 * 可以类比基于XML的工厂方法实例化bean那部分。
	 * <p>
	 * 对于使用@Bean注册的bean，它的默认命名策略就是取方法名作为bean的名字。@Bean一般用于注册外部jar包中的类，因为这些类不能的源码
	 * 不能够改，不能添加注解，此时只有使用@Bean的方式了。实际上@Bean注解更多的使用在@Configuration配置注解类内部，@Bean里面也有很
	 * 多配置可以设置，
	 */
	@Bean
	public Integer luckyInteger() {
		return 7;
	}

	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
		System.out.println(context.getBean("luckyInteger"));
		System.out.println("----@Component和@Bean singleton 的bean，在创建容器时就会初始化----");
		System.out.println(context.getBean("scopeO", ScopeDemo.ScopeO.class));
		System.out.println(context.getBean("scopeO", ScopeDemo.ScopeO.class));
		System.out.println(context.getBean("scopeA", ScopeDemo.ScopeA.class));
		System.out.println(context.getBean("scopeA", ScopeDemo.ScopeA.class));
		System.out.println(context.getBean("scopeB", ScopeDemo.ScopeB.class));
		System.out.println(context.getBean("scopeB", ScopeDemo.ScopeB.class));
		System.out.println(context.getBean("getScopeDemo1", ScopeDemo.class));
		System.out.println(context.getBean("getScopeDemo1", ScopeDemo.class));
		System.out.println("----@Component和@Bean prototype的bean，在获取时才会初始化----");
		System.out.println(context.getBean("scopeC", ScopeDemo.ScopeC.class));
		System.out.println(context.getBean("scopeC", ScopeDemo.ScopeC.class));
		System.out.println(context.getBean("getScopeDemo2", ScopeDemo.class));
		System.out.println(context.getBean("getScopeDemo2", ScopeDemo.class));
	}
}
